import 'dart:async';
import 'dart:convert';
import 'package:http/http.dart' as http;
import 'package:jtlf/common/consts.dart';
import 'package:shared_preferences/shared_preferences.dart';

class HttpUtils {
  final String baseUrl = serverUrl;
  Map<String, String> defaultHeaders = {
    'Content-Type': 'application/x-protobuf; charset=UTF-8',
  };
  final http.Client _client = http.Client();

  HttpUtils({
    Map<String, String>? headers,
  }) : defaultHeaders = {
    'Content-Type': 'application/x-protobuf; charset=UTF-8',
    ...?headers,
  };

  // 通用请求方法
  Future<dynamic> request({
    required String method,
    required String path,
    dynamic data, // dynamic 是可以为null的。这里的data，调用者应该封装好
    Map<String, String>? headers,
    Duration timeout = const Duration(seconds: 10),
  }) async {
    final url = Uri.parse('$baseUrl$path');
    // 从 SharedPreferences 获取认证信息
    final prefs = await SharedPreferences.getInstance(); // 构造函数中不能使用async，还是在请求方法中拦截吧
    final token = prefs.getString('auth_token');
    final userId = prefs.getString('user_id');
    final tenantId = prefs.getString('tenant_id');

    Map<String, String> authInfo = {};
    if (token != null) {
      authInfo['Authorization'] = token;
      authInfo['tokenId'] = token;
    }
    if (userId != null) {
      authInfo['userId'] = userId;
    }
    if (tenantId != null) {
      authInfo['tenantId'] = tenantId;
    }

    final mergedHeaders = {...defaultHeaders, ...?headers, ...authInfo};

    try {
      // 修复点1：正确构建请求对象
      final request = http.Request(method, url);
      request.headers.addAll(mergedHeaders);
      if (data != null) {
        // 这里如果不是json，不应该是这样的，需要优化
        // request.body = jsonEncode(data);
        request.body = data;
      }

      // 修复点2：使用 client.send 发送请求
      final response = await _client.send(request)
          .timeout(timeout, onTimeout: () => throw TimeoutException('Request timed out'));

      // return _handleResponse(await http.Response.fromStream(response));
      return await http.Response.fromStream(response);
    } catch (e) {
      _handleError(e);
      rethrow;
    } finally {
      _client.close();
    }
  }

  // GET
  Future<dynamic> get(
      String path, {
        Map<String, String>? headers,
        Duration timeout = const Duration(seconds: 10),
      }) =>
      request(
        method: 'GET',
        path: path,
        headers: headers,
        timeout: timeout,
      );

  // POST
  Future<dynamic> post(
      String path, {
        dynamic data,
        Map<String, String>? headers,
        Duration timeout = const Duration(seconds: 10),
      }) =>
      request(
        method: 'POST',
        path: path,
        data: data,
        headers: headers,
        timeout: timeout,
      );

  // PUT
  Future<dynamic> put(
      String path, {
        dynamic data,
        Map<String, String>? headers,
        Duration timeout = const Duration(seconds: 10),
      }) =>
      request(
        method: 'PUT',
        path: path,
        data: data,
        headers: headers,
        timeout: timeout,
      );

  // DELETE
  Future<dynamic> delete(
      String path, {
        dynamic data,
        Map<String, String>? headers,
        Duration timeout = const Duration(seconds: 10),
      }) =>
      request(
        method: 'DELETE',
        path: path,
        data: data,
        headers: headers,
        timeout: timeout,
      );

  // 处理响应
  dynamic _handleResponse(http.Response response) {
    final statusCode = response.statusCode;
    final responseBody = utf8.decode(response.bodyBytes);

    if (statusCode >= 200 && statusCode < 300) {
      if (responseBody.isEmpty) return null;
      // 这里不能直接解析，还是要用户自己来解析。如果是json的话，到是可以直接解析
      return jsonDecode(responseBody);
    } else {
      throw HttpException(
        statusCode: statusCode,
        message: responseBody.isNotEmpty
            ? jsonDecode(responseBody)['message'] ?? 'Request failed'
            : 'Request failed',
      );
    }
  }

  // 统一错误处理
  void _handleError(dynamic error) {
    if (error is TimeoutException) {
      throw const HttpException(message: 'Request timeout');
    } else if (error is http.ClientException) {
      throw HttpException(message: error.message);
    } else {
      throw HttpException(message: error.toString());
    }
  }
}

// 自定义异常类
class HttpException implements Exception {
  final int? statusCode;
  final String message;

  const HttpException({
    this.statusCode,
    required this.message,
  });

  @override
  String toString() =>
      'HttpException: ${statusCode ?? ''} - ${message.isNotEmpty ? message : 'Unknown error'}';
}
